package com.spzx.common.rabbit.config;

import com.alibaba.fastjson2.JSON;
import com.spzx.common.rabbit.entity.GuiguCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author Haoran Sun
 * @since 2024/08/02
 */

@Component
@Slf4j
public class RabbitInitConfigApplicationListener
        implements ApplicationListener<ApplicationReadyEvent> {

    private final RabbitTemplate rabbitTemplate;
    private final RedisTemplate<String, String> redisTemplate;

    public RabbitInitConfigApplicationListener(RabbitTemplate rabbitTemplate, RedisTemplate<String, String> redisTemplate) {
        this.rabbitTemplate = rabbitTemplate;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        setupCallbacks();
    }

    private void setupCallbacks() {
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                log.info("消息发送成功: {}", correlationData);
            } else {
                log.error("消息发送失败: {}", cause);
                assert correlationData != null;
                reSendMsg((GuiguCorrelationData) correlationData);
            }
        });

        rabbitTemplate.setReturnsCallback((returnMsg) -> {
            log.error("消息丢失: {}", returnMsg.getMessage());

            GuiguCorrelationData correlationData = JSON.parseObject(
                    redisTemplate
                            .opsForValue()
                            .get(returnMsg.getMessage()
                                    .getMessageProperties()
                                    .getHeader("spring_returned_message_correlation")), GuiguCorrelationData.class);
            assert correlationData != null;
            if (correlationData.isDelay()) {
                return;
            }
            reSendMsg(correlationData);
        });
    }

    private void reSendMsg(GuiguCorrelationData correlationData) {


        int retryCount = correlationData.getRetryCount();
        if (retryCount >= 3) {
            log.error("消息重试次数已超过3次，不再重试");
            return;
        }
        retryCount++;
        correlationData.setRetryCount(retryCount);
        //设置消息重试次数
        redisTemplate.opsForValue().set(
                correlationData.getId(),
                JSON.toJSONString(correlationData),
                10,
                TimeUnit.SECONDS
        );

        if (correlationData.isDelay()) {
            rabbitTemplate.convertAndSend(correlationData.getExchange(),
                    correlationData.getRoutingKey(),
                    correlationData.getMessage(),
                    (message) -> {
                        message.getMessageProperties().setDelay(correlationData.getDelayTime() * 1000);
                        return message;
                    },
                    correlationData);
        } else {
            rabbitTemplate.convertAndSend(
                    correlationData.getExchange(),
                    correlationData.getRoutingKey(),
                    correlationData.getMessage(),
                    correlationData);
        }


    }
}
